interface ApiResponse<T = unknown> {
  code: number
  data: T
  msg: string
}

export class RequestError extends Error {
  code: number
  msg: string

  constructor(options: { code: number, msg: string }) {
    super(options.msg)
    this.name = 'RequestError'
    this.code = options.code
    this.msg = options.msg
  }
}

export class HttpError extends Error {
  cause?: Error

  constructor(options: { cause?: Error }) {
    super('HTTP Error')
    this.name = 'HttpError'
    this.cause = options.cause
  }
}

export class UnknownException extends Error {
  error: unknown

  constructor(options: { error: unknown }) {
    super('Unknown Exception')
    this.name = 'UnknownException'
    this.error = options.error
  }
}

export async function tryApi<Data>(request: () => Promise<ApiResponse<Data>>): Promise<Data> {
  try {
    const response = await request()
    const { code, data, msg } = response

    if (code === 0) {
      return data
    }
    else {
      throw new RequestError({ code, msg })
    }
  }
  catch (error) {
    if (error instanceof RequestError) {
      throw error
    }
    else if (error instanceof Error) {
      throw new HttpError({ cause: error })
    }
    else {
      throw new UnknownException({ error })
    }
  }
}
